//! trait 相关方法实现
use proc_macro::TokenStream;
use quote::quote;
use syn::MetaNameValue;

/// 结构体相关方法实现
mod struct_tool;

/// 为请求报文自动实现为请求报文自动实现TinyOrmDbModel
pub(super) fn impl_tiny_orm(ast: &syn::DeriveInput) -> TokenStream {
    let struct_name = &ast.ident;
    let table_name = get_table_name(ast);

    let struct_tool::instance_method_impl::TinyOrmStructInfo {
        token: struct_impl,
        pk_where_sql,
        select_join_sql,
        select_field,
        update_set_field,
    } = struct_tool::impl_struct_fn(ast, &table_name);
    //dbg!(&struct_impl);
    // 使用主键更新所有字段
    let update_set_sql = format!("UPDATE {} SET {} ", table_name, update_set_field);
    let update_sql = format!("{update_set_sql} where {pk_where_sql}");
    let select_sql = format!(
        "SELECT {} FROM {} {} ",
        select_field,
        table_name,
        select_join_sql.unwrap_or_else(|| "".into())
    );
    let db_model_impl = quote! {
        impl TinyOrmDbModel for #struct_name {
            const DB_META:TinyOrmDbMeta = TinyOrmDbMeta{
                table_name: #table_name,
                select_sql: #select_sql,
                update_sql: #update_sql,
                update_set_sql: #update_set_sql,
                pk_where_sql: #pk_where_sql,
            };
        }
    };
    quote! {
        // ==== tiny orm auto impl TinyOrmDbModel Trait ====
        #db_model_impl
        // ==== tiny orm auto impl struct fn ====
        #struct_impl
    }
    .into()
}

/// 获取属性值
///
/// # 参数说明
///
/// * attrs Derive的属性列表
/// * key 要获取的属性名称
fn get_attribute_value(attrs: &[(String, String)], key: &str) -> Option<String> {
    attrs.iter().find_map(|(name, value)| {
        if name == key {
            Some(value.clone())
        } else {
            None
        }
    })
}
/// 根据属性值生成TinyDBMeta的各字段内容
///
/// # 参数说明
///
/// * attrs Derive的属性列表
/// * struct_name 对应结构体名称
fn get_table_name(ast: &syn::DeriveInput) -> String {
    let struct_name = &ast.ident;
    let attrs: Vec<_> = ast
        .attrs
        .iter()
        .filter(|attr| {
            attr.path.is_ident("orm_table_name") || attr.path.is_ident("orm_table_name_pref")
        })
        .map(|attr| {
            let name = attr.path.get_ident().unwrap().to_string();
            let meta = attr.parse_meta();
            let value = match meta {
                Ok(meta) => {
                    if let syn::Meta::NameValue(MetaNameValue { lit, .. }) = meta {
                        match lit {
                            syn::Lit::Str(s) => s.value(),
                            _ => panic!("orm属性设置错误,输入为字符串"),
                        }
                    } else {
                        panic!("orm属性设置错误,输入为字符串")
                    }
                }
                Err(_) => panic!("orm属性设置错误,输入为字符串"),
            };
            //let value = attr.to_owned().tokens.into_iter().nth(1).unwrap();
            (name, value)
        })
        .collect();
    let table_name_pref = get_attribute_value(&attrs, "orm_table_name_pref");
    get_attribute_value(&attrs, "orm_table_name").unwrap_or_else(|| {
        // 未指定自定义表名称，自动将结构名称转换为蛇形的表名称
        // CoreUser 转换为 core_user
        let mut table_name = String::new();
        for (i, ch) in struct_name.to_string().char_indices() {
            if i > 0 && ch.is_uppercase() {
                table_name.push('_');
            }
            table_name.push(ch.to_ascii_lowercase());
        }
        if let Some(table_name_pref) = table_name_pref {
            format!("{table_name_pref}_{table_name}")
        } else {
            table_name
        }
    })
}
